/*
 * COPYRIGHT. ShenZhen JiMi Technology Co., Ltd. 2017.
 * ALL RIGHTS RESERVED.
 *
 * No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
 * on any form or by any means, electronic, mechanical, photocopying, recording, 
 * or otherwise, without the prior written permission of ShenZhen JiMi Network Technology Co., Ltd.
 *
 * Amendment History:
 * 
 * Date                   By              Description
 * -------------------    -----------     -------------------------------------------
 * 2017年4月5日    li.shangzhi         Create the class
 * http://www.jimilab.com/
 */

package com.jimi.gateway.route;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;

import com.jimi.app.api.IApiGatewayRouteInfoApi;
import com.jimi.app.dto.input.ApiGatewayRouteInfoInputDto;
import com.jimi.app.dto.output.ApiGatewayRouteInfoOutputDto;
import com.jimi.framework.context.SpringContextHolder;

/**
 * @FileName CustomRouteLocator.java
 * @Description: 自定义路由定位器
 *
 * @Date 2017年4月5日 下午1:36:50
 * @author li.shangzhi
 * @version 1.0
 */
public class CustomRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

	private static final Logger logger = LoggerFactory.getLogger(CustomRouteLocator.class);

	private ZuulProperties properties;

//	private JdbcTemplate jdbcTemplate;

//	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
//		this.jdbcTemplate = jdbcTemplate;
//	}

	public CustomRouteLocator(String servletPath, ZuulProperties properties) {
		super(servletPath, properties);
		this.properties = properties;
		logger.info("servletPath:{}", servletPath);
	}

	// 父类已经提供了这个方法，这里写出来只是为了说明这一个方法很重要！！！
	// @Override
	// protected void doRefresh() {
	// super.doRefresh();
	// }

	@Override
	public void refresh() {
		doRefresh();
	}

	@Override
	protected Map<String, ZuulRoute> locateRoutes() {
		LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();

		// 从application.properties中加载路由信息
		routesMap.putAll(super.locateRoutes());

		// 从db中加载路由信息
		routesMap.putAll(locateRoutesFromDB());

		// 参考DiscoveryClientRouteLocator类的实现，优化路径
		LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
		for (Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
			String path = entry.getKey();
			// Prepend with slash if not already present.
			if (!path.startsWith("/")) {
				path = "/" + path;
			}
			if (StringUtils.hasText(this.properties.getPrefix())) {
				path = this.properties.getPrefix() + path;
				if (!path.startsWith("/")) {
					path = "/" + path;
				}
			}
			values.put(path, entry.getValue());
		}

		return values;
	}

	/**
	 * @Title: locateRoutesFromDB
	 * @Description: 从数据库加载路由信息，目前采用spring jdbc实现，后续可以换成mybatis
	 * @return
	 * @author li.shangzhi
	 * @date 2017年4月5日 下午1:57:17
	 */
	private Map<String, ZuulRoute> locateRoutesFromDB() {
		Map<String, ZuulRoute> routes = new LinkedHashMap<>();
		IApiGatewayRouteInfoApi gatewayRouteInfoApi = SpringContextHolder.getBean(IApiGatewayRouteInfoApi.class);
		ApiGatewayRouteInfoInputDto inputDto = new ApiGatewayRouteInfoInputDto();
		inputDto.setEnabled(true);
		List<ApiGatewayRouteInfoOutputDto> lstApiGatewayRouteInfos = gatewayRouteInfoApi.findList(inputDto);
		if(null != lstApiGatewayRouteInfos && !lstApiGatewayRouteInfos.isEmpty()) {
			for(ApiGatewayRouteInfoOutputDto outputDto : lstApiGatewayRouteInfos) {
				if (org.apache.commons.lang3.StringUtils.isBlank(outputDto.getPath())
						|| org.apache.commons.lang3.StringUtils.isBlank(outputDto.getUrl())) {
					continue;
				}
				ZuulRoute zuulRoute = new ZuulRoute();
				try {
					org.springframework.beans.BeanUtils.copyProperties(outputDto, zuulRoute);
				} catch (Exception e) {
					logger.error("=============load zuul route info from db with error==============", e);
				}
				routes.put(zuulRoute.getPath(), zuulRoute);
			}
		}
//		List<ZuulRouteVo> results = jdbcTemplate.query("select * from t_api_gateway_route_info where enabled = true",
//				new BeanPropertyRowMapper<>(ZuulRouteVo.class));
//		for (ZuulRouteVo result : results) {
//			if (org.apache.commons.lang3.StringUtils.isBlank(result.getPath())
//					|| org.apache.commons.lang3.StringUtils.isBlank(result.getUrl())) {
//				continue;
//			}
//			ZuulRoute zuulRoute = new ZuulRoute();
//			try {
//				org.springframework.beans.BeanUtils.copyProperties(result, zuulRoute);
//			} catch (Exception e) {
//				logger.error("=============load zuul route info from db with error==============", e);
//			}
//			routes.put(zuulRoute.getPath(), zuulRoute);
//		}
		return routes;
	}
}
